home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-01-03 | 30.3 KB | 1,591 lines |
- Newsgroups: comp.sources.unix
- From: gls@cbnewsh.att.com (Col. G. L. Sicherman)
- Subject: v25i091: roff - simple text formatter
- Sender: sources-moderator@pa.dec.com
- Approved: vixie@pa.dec.com
-
- Submitted-By: gls@cbnewsh.att.com (Col. G. L. Sicherman)
- Posting-Number: Volume 25, Issue 91
- Archive-Name: roff
-
- [ I'm posting this because people keep asking for it.
- It's essentially the same as the version in MINIX.
- --gls ]
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: roff.1 roff.c Makefile
- # Wrapped by vixie@cognition.pa.dec.com on Fri Jan 3 17:49:57 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'roff.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'roff.1'\"
- else
- echo shar: Extracting \"'roff.1'\" \(6693 characters\)
- sed "s/^X//" >'roff.1' <<'END_OF_FILE'
- X.TH ROFF 1 "19 May 1983"
- X.SH NAME
- roff \- format text
- X.SH SYNOPSIS
- X.B \*(Bd/roff
- X[ \fB+\fIn\fR ] [ \fB\-\fIn\fR ] [
- X.B \-s
- X] [
- X.B \-h
- X] file ...
- X.PP
- X.B nroff \-mr
- X[ option ] ... file ...
- X.br
- X.B troff \-mr
- X[ option ] ... file ...
- X.SH DESCRIPTION
- X.I Roff
- formats text according to control lines embedded
- in the text in the given files.
- XEncountering a nonexistent file terminates printing.
- Incoming inter-terminal messages are turned off during printing.
- The optional flag arguments mean:
- X.br
- X.ns
- X.TP 5
- X.BI + n
- Start printing at the first page with number
- X.IR n .
- X.br
- X.ns
- X.TP 5
- X.BI \- n
- Stop printing at the first page numbered higher
- than
- X.IR n .
- X.br
- X.ns
- X.TP 5
- X.B \-s
- Stop before each page (including the first)
- to allow paper manipulation;
- resume on receipt of an interrupt signal.
- X.br
- X.ns
- X.TP 5
- X.B \-h
- Insert tabs in the output stream to replace
- spaces whenever appropriate.
- X.PP
- X.DT
- Input consists of intermixed
- X.I "text lines,"
- which contain information to be formatted, and
- X.I "request lines,"
- which contain instructions about how to format
- it.
- Request lines begin with a distinguished
- X.I "control character,"
- normally a period.
- X.PP
- Output lines may be
- X.I filled
- as nearly as possible with words without regard to
- input lineation.
- Line
- X.I breaks
- may be caused at specified places by
- certain commands, or by the appearance of an
- empty input line or an input line beginning with a space.
- X.PP
- The capabilities of
- X.I roff
- are specified in the attached Request Summary.
- Numerical values are denoted there by n or +n,
- titles by t, and single characters by c.
- Numbers denoted +n may be signed + or \-,
- in which case they signify relative changes to
- a quantity, otherwise they signify
- an absolute resetting.
- Missing n fields are ordinarily taken to be 1,
- missing t fields to be empty, and c fields to shut off
- the appropriate special interpretation.
- X.PP
- Running titles usually appear at top and bottom of every
- page.
- They are set by requests like
- X.PP
- X.in +10
- X.if t \&.he \(fmpart1\(fmpart2\(fmpart3\(fm
- X.if n \&.he 'part1'part2'part3'
- X.in -10
- X.PP
- Part1 is left justified, part2 is centered,
- and part3 is right justified on the page.
- Any % sign in a title is replaced by the current
- page number.
- Any nonblank may serve as a quote.
- X.PP
- ASCII tab characters are replaced in the input by a
- X.I "replacement character,"
- normally a space,
- according to the
- column settings given by a .ta command.
- X(See .tr for how to convert this character on output.)
- X.PP
- Automatic hyphenation of filled output is done
- under control of .hy.
- When a word contains a designated
- X.I "hyphenation character,"
- that character disappears from the output and
- hyphens can be introduced into
- the word at the marked places only.
- X.PP
- The
- X.B \-mr
- option of
- X.I nroff
- or
- X.IR troff (1)
- simulates
- X.I roff
- to the greatest extent possible.
- X.SH FILES
- X.\" /usr/lib/suftab suffix hyphenation tables
- X.\" .br
- X/tmp/rtm* temporary
- X.br
- X.SH BUGS
- X.I Roff
- is the simplest of the text formatting
- programs, and is utterly frozen.
- X.PP
- This is a home-brewed C version of a V7 assembly-language program.
- It hyphenates only at hyphenation characters
- and comes with no guarantees.
- In particular, ridiculously long source lines will crash it.
- X.SH AUTHOR
- G. L. Sicherman (decvax!sunybcs!colonel)
- X.bp
- X.tc |
- X.tr |
- X.in 0
- X.ce
- REQUEST SUMMARY
- X.\" V7 man page used .li, which is not available in ditroff.
- X.\" Use \& throughout instead. --the Col.
- X.\".PP
- X.ul
- X.ta \w'.tr cdef.. 'u +\w'Break 'u +\w'Initial 'u
- X.di x
- X \ka
- X.br
- X.di
- X.in \nau
- X.ti 0
- Request Break Initial Meaning
- X.na
- X.ti 0
- X\&.ad yes yes Begin adjusting right margins.
- X.ti 0
- X\&.ar no arabic Arabic page numbers.
- X.ti 0
- X\&.br yes \- Causes a line break \- the filling of
- the current line is stopped.
- X.ti 0
- X\&.bl|n yes \- Insert of n blank lines, on new page if necessary.
- X.ti 0
- X\&.bp|+n yes n=1 Begin new page and number it n; no n means `+1'.
- X.ti 0
- X\&.cc|c no c=. Control character becomes `c'.
- X.ti 0
- X\&.ce|n yes \- Center the next n input lines,
- without filling.
- X.ti 0
- X\&.de|xx no \- Define parameterless macro
- to be invoked by request `.xx'
- X(definition ends on line beginning `\fB..\fR').
- X.ti 0
- X\&.ds yes no Double space; same as `.ls 2'.
- X.ti 0
- X\&.ef|t no t=\*a\*a\*a\*a Even foot title becomes t.
- X.ti 0
- X\&.eh|t no t=\*a\*a\*a\*a Even head title becomes t.
- X.ti 0
- X\&.fi yes yes Begin filling output lines.
- X.ti 0
- X\&.fo no t=\*a\*a\*a\*a All foot titles are t.
- X.ti 0
- X\&.hc|c no none Hyphenation character becomes `c'.
- X.ti 0
- X\&.he|t no t=\*a\*a\*a\*a All head titles are t.
- X.ti 0
- X\&.hx no \- Title lines are suppressed.
- X.ti 0
- X\&.hy|n no n=1 Hyphenation is done, if n=1;
- and is not done, if n=0.
- X.ti 0
- X\&.ig no \- Ignore input lines through
- a line beginning with `\fB..\fR'.
- X.ti 0
- X\&.in|+n yes \- Indent n spaces from left margin.
- X.ti 0
- X\&.ix +n no \- Same as `.in' but without break.
- X.ti 0
- X\&.li|n no \- Literal, treat next n lines as text.
- X.ti 0
- X\&.ll|+n no n=65 Line length including indent is n characters.
- X.ti 0
- X\&.ls|+n yes n=1 Line spacing set to n lines per output line.
- X.ti 0
- X\&.m1|n no n=2 Put n blank lines between the top
- of page and head title.
- X.ti 0
- X\&.m2|n no n=2 n blank lines put between head title
- and beginning of text on page.
- X.ti 0
- X\&.m3|n no n=1 n blank lines put between end of
- text and foot title.
- X.ti 0
- X\&.m4|n no n=3 n blank lines put between the foot title
- and the bottom of page.
- X.ti 0
- X\&.na yes no Stop adjusting the right margin.
- X.ti 0
- X\&.ne|n no \- Begin new page, if n output lines
- cannot fit on present page.
- X.ti 0
- X\&.nn|+n no \- The next n output lines are not numbered.
- X.ti 0
- X\&.n1 no no Add 5 to page offset;
- number lines in margin from 1 on each page.
- X.ti 0
- X\&.n2|n no no Add 5 to page offset;
- number lines from n;
- stop if n=0.
- X.ti 0
- X\&.ni|+n no n=0 Line numbers are indented n.
- X.ti 0
- X\&.nf yes no Stop filling output lines.
- X.ti 0
- X\&.nx|file no \- Switch input to `file'.
- X.ti 0
- X\&.of|t no t=\*a\*a\*a\*a Odd foot title becomes t.
- X.ti 0
- X\&.oh|t no t=\*a\*a\*a\*a Odd head title becomes t.
- X.ti 0
- X\&.pa|+n yes n=1 Same as `.bp'.
- X.ti 0
- X\&.pl|+n no n=66 Total paper length taken to be n lines.
- X.ti 0
- X\&.po|+n no n=0 Page offset.
- All lines are preceded by n spaces.
- X.ti 0
- X\&.ro no arabic Roman page numbers.
- X.ti 0
- X\&.sk|n no \- Produce n blank pages starting next page.
- X.ti 0
- X\&.sp|n yes \- Insert block of n blank lines,
- except at top of page.
- X.ti 0
- X\&.ss yes yes Single space output lines,
- equivalent to `.ls 1'.
- X.ti 0
- X\&.ta|n|n.. \- Pseudotab settings.
- Initial tab settings are columns 9 17 25 ...
- X.ti 0
- X\&.tc|c no space Tab replacement character becomes `c'.
- X.ti 0
- X\&.ti|+n yes \- Temporarily indent next output
- line n spaces.
- X.ti0
- X\&.tr|cdef.. no \- Translate c into d, e into f, etc.
- X.ti0
- X\&.ul|n no \- Underline the letters and numbers
- in the next n input lines.
- X.br
- X.tr ||
- END_OF_FILE
- if test 6693 -ne `wc -c <'roff.1'`; then
- echo shar: \"'roff.1'\" unpacked with wrong size!
- fi
- # end of 'roff.1'
- fi
- if test -f 'roff.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'roff.c'\"
- else
- echo shar: Extracting \"'roff.c'\" \(20604 characters\)
- sed "s/^X//" >'roff.c' <<'END_OF_FILE'
- X/*
- X * roff - C version.
- X * the Colonel. 19 May 1983.
- X *
- X * Copyright 1983 by G. L. Sicherman.
- X * You may use and alter this software freely for noncommercial ends
- X * so long as you leave this message alone.
- X *
- X * Fix by Tim Maroney, 31 Dec 1984.
- X * .hc implemented, 8 Feb 1985.
- X * Fix to hyphenating with underlining, 12 Feb 1985.
- X * Fixes to long-line hang and .bp by Dave Tutelman, 30 Mar 1985.
- X * Fix to centering valve with long input lines, 4 May 1987.
- X */
- X
- X#include <sgtty.h>
- X#include <signal.h>
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X/* MAXMAC - maximum number of macros. */
- X#define MAXMAC 64
- X/* MAXDEPTH - maximum recursion of macros. */
- X#define MAXDEPTH 10
- X#define MAXLENGTH 255
- X#define UNDERL '\200'
- X#define SUFTAB "/usr/lib/suftab"
- X#define TXTLEN (o_pl-o_m1-o_m2-o_m3-o_m4-2)
- X#define IDTLEN (o_ti>=0?o_ti:o_in)
- X
- char spacechars[] = " \t\n";
- int sflag, hflag, startpage, stoppage;
- char holdword[MAXLENGTH], *holdp;
- char assyline[MAXLENGTH];
- int assylen;
- char ehead[100], efoot[100], ohead[100], ofoot[100];
- struct macrotype {
- X char mname[3];
- X long int moff;
- X} macro[MAXMAC];
- int n_macros;
- int depth;
- int adjtoggle;
- int isrequest = 0;
- char o_tr[40][2]; /* OUTPUT TRANSLATION TABLE */
- int o_cc = '.'; /* CONTROL CHARACTER */
- int o_hc = -1; /* HYPHENATION CHARACTER */
- int o_tc = ' '; /* TABULATION CHARACTER */
- int o_in = 0; /* INDENT SIZE */
- int o_ix = -1; /* NEXT INDENT SIZE */
- int o_ta[20] = {
- X 9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105,
- X 113, 121, 129, 137, 145, 153, 161};
- int n_ta = 20; /* #TAB STOPS */
- int o_ll = 65, o_ad = 1, o_po = 0, o_ls = 1, o_ig = 0, o_fi = 1;
- int o_pl = 66, o_ro = 0, o_hx = 0, o_bl = 0, o_sp = 0, o_sk = 0;
- int o_ce = 0, o_m1 = 2, o_m2 = 2, o_m3 = 1, o_m4 = 3, o_ul = 0;
- int o_li = 0, o_n1 = 0, o_n2 = 0, o_bp = -1, o_hy = 1;
- int o_ni = 1; /* LINE-NUMBER INDENT */
- int o_nn = 0; /* #LINES TO SUPPRESS NUMBERING */
- int o_ti = -1; /* TEMPORARY INDENT */
- int page_no = -1;
- int line_no = 9999;
- int n_outwords;
- XFILE *File, *Macread, *Macwrite;
- XFILE *Save;
- long int teller[MAXDEPTH], ftell();
- char *strcat(), *strcpy(), *strend(), *strhas();
- char *sprintf();
- char *request[] = {
- X "ad","ar","bl","bp","br","cc","ce","de",
- X "ds","ef","eh","fi","fo","hc","he","hx","hy","ig",
- X "in","ix","li","ll","ls","m1","m2","m3","m4",
- X "n1","n2","na","ne","nf","ni","nn","nx","of","oh",
- X "pa","pl","po","ro","sk","sp","ss","ta","tc","ti",
- X "tr","ul",0};
- char *mktemp(), *mfilnam = "/tmp/rtmXXXXXX";
- int c; /* LAST CHAR READ */
- struct sgttyb tty;
- X
- main(argc,argv)
- int argc;
- char **argv;
- X{
- X while (--argc) switch (**++argv) {
- X case '+':
- X startpage=atoi(++*argv);
- X break;
- X case '-':
- X ++*argv;
- X if (isdigit(**argv)) stoppage=atoi(*argv);
- X else switch(**argv) {
- X case 's':
- X sflag++;
- X break;
- X case 'h':
- X hflag++;
- X break;
- X default:
- X bomb();
- X }
- X break;
- X default:
- X argc++;
- X goto endargs;
- X }
- endargs:
- X if (sflag) gtty(0,&tty);
- X mesg(0); /* BLOCK OUT MESSAGES */
- X assylen=0;
- X assyline[0]='\0';
- X if (!argc) {
- X File=stdin;
- X readfile();
- X }
- X else while (--argc) {
- X File=fopen(*argv,"r");
- X if (NULL==File) {
- X fprintf(stderr,"roff: cannot read %s\n",*argv);
- X exit(1);
- X }
- X readfile();
- X fclose(File);
- X argv++;
- X }
- X writebreak(); /* TERMINATE PARTIAL OUTPUT LINE */
- X endpage(); /* FLUSH LAST PAGE */
- X for (; o_sk; o_sk--) blankpage(); /* FLUSH BLANK PAGES */
- X mesg(1); /* ALLOW MESSAGES */
- X}
- X
- mesg(f)
- int f;
- X{
- X static int mode;
- X struct stat cbuf;
- X char *ttyname();
- X
- X if (!isatty(1)) return;
- X if (!f) {
- X fstat(1,&cbuf);
- X mode = cbuf.st_mode;
- X chmod(ttyname(1),mode & ~022);
- X }
- X else chmod(ttyname(1),mode);
- X}
- X
- readfile()
- X{
- X while (readline()) {
- X if (isrequest) continue;
- X if (o_ce || !o_fi) {
- X if (assylen) writeline(0,1);
- X else blankline();
- X if (o_ce) o_ce--;
- X }
- X }
- X}
- X
- readline()
- X{
- X int startline, doingword;
- X isrequest = 0;
- X startline = 1;
- X doingword = 0;
- X c=suck();
- X if (c == '\n') {
- X o_sp = 1;
- X writebreak();
- X goto out;
- X }
- X else if (isspace(c)) writebreak();
- X for (;;) {
- X if (c==EOF) { /* EOF - FLUSH WORD, IF ANY */
- X if (doingword) bumpword();
- X break;
- X }
- X if (c!=o_cc && o_ig) { /* IGNORE A TEXT LINE */
- X while (c!='\n' && c!=EOF) c=suck();
- X break;
- X }
- X if (isspace(c) && !doingword) {
- X startline=0;
- X switch (c) {
- X case ' ':
- X assyline[assylen++]=' ';
- X break;
- X case '\t':
- X tabulate();
- X break;
- X case '\n':
- X goto out;
- X }
- X c = suck();
- X continue;
- X }
- X if (isspace(c) && doingword) { /* WHITE SPACE - FLUSH WORD */
- X bumpword();
- X if (c=='\t') tabulate();
- X else if (assylen) assyline[assylen++]=' ';
- X doingword=0;
- X if (c=='\n') break;
- X }
- X if (!isspace(c)) {
- X/*
- X * It's not a space. If we're doing a word, continue it.
- X * If it's a request, process it.
- X */
- X if (doingword) *holdp++ = o_ul? c|UNDERL: c;
- X else if (startline && c==o_cc && !o_li) {
- X isrequest=1;
- X return readreq();
- X }
- X/*
- X * It's the start of a new word. Store it.
- X */
- X else {
- X doingword=1;
- X holdp=holdword;
- X *holdp++ = o_ul? c|UNDERL: c;
- X }
- X }
- X startline=0;
- X c = suck();
- X }
- out:
- X if (o_ul) o_ul--;
- X if (o_li) o_li--;
- X return c!=EOF;
- X}
- X
- X/*
- X * bumpword - add word to current line.
- X */
- X
- bumpword()
- X{
- X char *hc;
- X *holdp = '\0';
- X/*
- X * Tutelman's fix #1, modified by the Colonel.
- X */
- X if (!o_fi || o_ce) goto giveup;
- X/*
- X * We use a while-loop in case of ridiculously long words with
- X * multiple hyphenation indicators.
- X */
- X if (assylen + reallen(holdword) > o_ll - IDTLEN) {
- X if (!o_hy) writeline(o_ad,0);
- X else while (assylen + reallen(holdword) > o_ll - IDTLEN) {
- X/*
- X * Try hyphenating it.
- X */
- X if (o_hc && strhas(holdword,o_hc)) {
- X/*
- X * There are hyphenation marks. Use them!
- X */
- X for (hc=strend(holdword); hc>=holdword; hc--) {
- X if ((*hc&~UNDERL)!=o_hc) continue;
- X *hc = '\0';
- X if (assylen + reallen(holdword) + 1 >
- X o_ll - IDTLEN) {
- X *hc = o_hc;
- X continue;
- X }
- X/*
- X * Yay - it fits!
- X */
- X dehyph(holdword);
- X strcpy(&assyline[assylen],holdword);
- X strcat(assyline,"-");
- X assylen += strlen(holdword) + 1;
- X strcpy(holdword,++hc);
- X break; /* STOP LOOKING */
- X } /* for */
- X/*
- X * It won't fit, or we've succeeded in breaking the word.
- X */
- X writeline(o_ad,0);
- X if (hc<holdword) goto giveup;
- X }
- X else {
- X/*
- X * If no hyphenation marks, give up.
- X * Let somebody else implement it.
- X */
- X writeline(o_ad,0);
- X goto giveup;
- X }
- X } /* while */
- X }
- giveup:
- X/*
- X * remove hyphenation marks, even if hyphenation is disabled.
- X */
- X if (o_hc) dehyph(holdword);
- X strcpy(&assyline[assylen],holdword);
- X assylen+=strlen(holdword);
- X holdp = holdword;
- X}
- X
- X/*
- X * dehyph - remove hyphenation marks.
- X */
- X
- dehyph(s)
- char *s;
- X{
- X char *t;
- X for (t=s; *s; s++) if ((*s&~UNDERL) != o_hc) *t++ = *s;
- X *t='\0';
- X}
- X
- X/*
- X * reallen - length of a word, excluding hyphenation marks.
- X */
- X
- int
- reallen(s)
- char *s;
- X{
- X register n;
- X n=0;
- X while (*s) n += (o_hc != (~UNDERL & *s++));
- X return n;
- X}
- X
- tabulate()
- X{
- X int j;
- X for (j=0; j<n_ta; j++) if (o_ta[j]-1>assylen+IDTLEN) {
- X for (; assylen+IDTLEN<o_ta[j]-1; assylen++)
- X assyline[assylen]=o_tc;
- X return;
- X }
- X /* NO TAB STOPS REMAIN */
- X assyline[assylen++]=o_tc;
- X}
- X
- int
- readreq()
- X{
- X char req[3];
- X int r, s;
- X if (skipsp()) return c!=EOF;
- X c=suck();
- X if (c==EOF || c=='\n') return c!=EOF;
- X if (c=='.') {
- X o_ig = 0;
- X do (c=suck());
- X while (c!=EOF && c!='\n');
- X if (depth) endmac();
- X return c!=EOF;
- X }
- X if (o_ig) {
- X while (c!=EOF && c!='\n') c=suck();
- X return c!=EOF;
- X }
- X req[0]=c;
- X c=suck();
- X if (c==EOF || c=='\n') req[1]='\0';
- X else req[1]=c;
- X req[2]='\0';
- X for (r=0; r<n_macros; r++) if (!strcmp(macro[r].mname,req)) {
- X/*
- X * It's a macro. Invoke it.
- X */
- X submac(r);
- X goto reqflsh;
- X }
- X for (r=0; request[r]; r++) if (!strcmp(request[r],req)) break;
- X if (!request[r]) {
- X/*
- X * Invalid request. Ignore it.
- X */
- X do (c=suck());
- X while (c!=EOF && c!='\n');
- X return c!=EOF;
- X }
- X switch (r) {
- X case 0: /* ad */
- X o_ad=1;
- X writebreak();
- X break;
- X case 1: /* ar */
- X o_ro=0;
- X break;
- X case 2: /* bl */
- X nread(&o_bl);
- X writebreak();
- X break;
- X case 3: /* bp */
- X case 37: /* pa */
- X c=snread(&r,&s,1);
- X/*
- X * Tutelman's fix #2 - the signs were reversed!
- X */
- X if (s>0) o_bp=page_no+r;
- X else if (s<0) o_bp=page_no-r;
- X else o_bp=r;
- X writebreak();
- X if (line_no) {
- X endpage();
- X beginpage();
- X }
- X break;
- X case 4: /* br */
- X writebreak();
- X break;
- X case 5: /* cc */
- X c=cread(&o_cc);
- X break;
- X case 6: /* ce */
- X/*
- X * Fix to centering. Set counter _after_ breaking! --G.L.S.
- X */
- X nread(&r);
- X writebreak();
- X o_ce = r;
- X break;
- X case 7: /* de */
- X defmac();
- X break;
- X case 8: /* ds */
- X o_ls=2;
- X writebreak();
- X break;
- X case 9: /* ef */
- X c=tread(efoot);
- X break;
- X case 10: /* eh */
- X c=tread(ehead);
- X break;
- X case 11: /* fi */
- X o_fi=1;
- X writebreak();
- X break;
- X case 12: /* fo */
- X c=tread(efoot);
- X strcpy(ofoot,efoot);
- X break;
- X case 13: /* hc */
- X c=cread(&o_hc);
- X break;
- X case 14: /* he */
- X c=tread(ehead);
- X strcpy(ohead,ehead);
- X break;
- X case 15: /* hx */
- X o_hx=1;
- X break;
- X case 16: /* hy */
- X nread(&o_hy);
- X break;
- X case 17: /* ig */
- X o_ig=1;
- X break;
- X case 18: /* in */
- X writebreak();
- X snset(&o_in);
- X o_ix = -1;
- X break;
- X case 19: /* ix */
- X snset(&o_ix);
- X if (!n_outwords) o_in=o_ix;
- X break;
- X case 20: /* li */
- X nread(&o_li);
- X break;
- X case 21: /* ll */
- X snset(&o_ll);
- X break;
- X case 22: /* ls */
- X snset(&o_ls);
- X break;
- X case 23: /* m1 */
- X nread(&o_m1);
- X break;
- X case 24: /* m2 */
- X nread(&o_m2);
- X break;
- X case 25: /* m3 */
- X nread(&o_m3);
- X break;
- X case 26: /* m4 */
- X nread(&o_m4);
- X break;
- X case 27: /* n1 */
- X o_n1=1;
- X break;
- X case 28: /* n2 */
- X nread(&o_n2);
- X break;
- X case 29: /* na */
- X o_ad=0;
- X writebreak();
- X break;
- X case 30: /* ne */
- X nread(&r);
- X if (line_no+(r-1)*o_ls+1 > TXTLEN) {
- X writebreak();
- X endpage();
- X beginpage();
- X }
- X break;
- X case 31: /* nf */
- X o_fi=0;
- X writebreak();
- X break;
- X case 32: /* ni */
- X snset(&o_ni);
- X break;
- X case 33: /* nn */
- X snset(&o_nn);
- X break;
- X case 34: /* nx */
- X do_nx();
- X c='\n'; /* SO WE DON'T FLUSH THE FIRST LINE */
- X break;
- X case 35: /* of */
- X c=tread(ofoot);
- X break;
- X case 36: /* oh */
- X c=tread(ohead);
- X break;
- X case 38: /* pl */
- X snset(&o_pl);
- X break;
- X case 39: /* po */
- X snset(&o_po);
- X break;
- X case 40: /* ro */
- X o_ro=1;
- X break;
- X case 41: /* sk */
- X nread(&o_sk);
- X break;
- X case 42: /* sp */
- X nread(&o_sp);
- X writebreak();
- X break;
- X case 43: /* ss */
- X writebreak();
- X o_ls=1;
- X break;
- X case 44: /* ta */
- X do_ta();
- X break;
- X case 45: /* tc */
- X c=cread(&o_tc);
- X break;
- X case 46: /* ti */
- X writebreak();
- X c=snread(&r,&s,0);
- X if (s>0) o_ti=o_in+r;
- X else if (s<0) o_ti=o_in-r;
- X else o_ti=r;
- X break;
- X case 47: /* tr */
- X do_tr();
- X break;
- X case 48: /* ul */
- X nread(&o_ul);
- X break;
- X }
- reqflsh:
- X while (c!=EOF && c!='\n') c=suck();
- X return c!=EOF;
- X}
- X
- X/*
- X * snset - set a value upwards, downwards, or absolutely.
- X */
- X
- snset(par)
- int *par;
- X{
- X int r, s;
- X c=snread(&r,&s,0);
- X if (s>0) *par+=r;
- X else if (s<0) *par-=r;
- X else *par=r;
- X}
- X
- tread(s)
- char *s;
- X{
- X int leadbl;
- X leadbl=0;
- X for (;;) {
- X c=suck();
- X if (c==' ' && !leadbl) continue;
- X if (c==EOF || c=='\n') {
- X *s = '\0';
- X return c;
- X }
- X *s++ = c;
- X leadbl++;
- X }
- X}
- X
- nread(i)
- int *i;
- X{
- X int f;
- X f=0;
- X *i=0;
- X if (!skipsp()) for (;;) {
- X c=suck();
- X if (c==EOF) break;
- X if (isspace(c)) break;
- X if (isdigit(c)) {
- X f++;
- X *i = *i*10 + c - '0';
- X }
- X else break;
- X }
- X if (!f) *i=1;
- X}
- X
- int
- snread(i,s,sdef)
- int *i, *s, sdef;
- X{
- X int f;
- X f = *i = *s = 0;
- X for (;;) {
- X c=suck();
- X if (c==EOF || c=='\n') break;
- X if (isspace(c)) {
- X if (f) break;
- X else continue;
- X }
- X if (isdigit(c)) {
- X f++;
- X *i = *i*10 + c - '0';
- X }
- X else if ((c=='+' || c=='-') && !f) {
- X f++;
- X *s = c=='+' ? 1 : -1;
- X }
- X else break;
- X }
- X while (c!=EOF && c!='\n') c=suck();
- X if (!f) {
- X *i=1;
- X *s=sdef;
- X }
- X return c;
- X}
- X
- int
- cread(k)
- int *k;
- X{
- X int u;
- X *k = -1;
- X for (;;) {
- X u=suck();
- X if (u==EOF || u=='\n') return u;
- X if (isspace(u)) continue;
- X if (*k < 0) *k=u;
- X }
- X}
- X
- X/*
- X * defmac - define a macro.
- X */
- X
- defmac()
- X{
- X int i;
- X char newmac[3], *nm;
- X if (skipsp()) return;
- X nm=newmac;
- X if (!Macwrite) openmac();
- X *nm++ = suck();
- X c=suck();
- X if (c!=EOF && c!='\n' && c!=' ' && c!='\t') *nm++ = c;
- X *nm = '\0';
- X /* KILL OLD DEFINITION IF ANY */
- X for (i=0; i<n_macros; i++) if (!strcmp(newmac,macro[i].mname)) {
- X macro[i].mname[0]='\0';
- X break;
- X }
- X macro[n_macros].moff=ftell(Macwrite);
- X strcpy(macro[n_macros++].mname,newmac); /* OVERFLOW HAZARD HERE! */
- X while (c!=EOF && c!='\n') c=suck(); /* FLUSH HEADER LINE */
- X while (copyline());
- X fflush(Macwrite);
- X}
- X
- openmac()
- X{
- X if (NULL==(Macwrite=fopen(mktemp(mfilnam),"w"))) {
- X fprintf(stderr,"roff: cannot open temp file\n");
- X exit(1);
- X }
- X Macread=fopen(mfilnam,"r");
- X unlink(mfilnam);
- X}
- X
- int
- copyline()
- X{
- X int n, first, second;
- X if (c==EOF) {
- X fprintf(Macwrite,"..\n");
- X return 0;
- X }
- X n=0;
- X first=1;
- X second=0;
- X for (;;) {
- X c=suck();
- X if (c==EOF) {
- X if (!first) putc('\n',Macwrite);
- X return 0;
- X }
- X if (c=='\n') {
- X putc('\n',Macwrite);
- X return n!=2;
- X }
- X if (first && c=='.') n++;
- X else if (second && n==1 && c=='.') n++;
- X putc(c,Macwrite);
- X second=first;
- X first=0;
- X }
- X}
- X
- submac(r)
- int r;
- X{
- X while (c!=EOF && c!='\n') c=suck();
- X if (depth) teller[depth-1]=ftell(Macread);
- X else {
- X Save = File;
- X File = Macread;
- X }
- X depth++;
- X fseek(Macread,macro[r].moff,0);
- X}
- X
- endmac()
- X{
- X depth--;
- X if (depth) fseek(Macread,teller[depth-1],0);
- X else File = Save;
- X c='\n';
- X}
- X
- do_ta()
- X{
- X int v;
- X n_ta = 0;
- X for (;;) {
- X nread(&v);
- X if (v==1) return;
- X else o_ta[n_ta++]=v;
- X if (c=='\n' || c==EOF) break;
- X }
- X}
- X
- do_tr()
- X{
- X char *t;
- X t = &o_tr[0][0];
- X *t='\0';
- X if (skipsp()) return;
- X for (;;) {
- X c=suck();
- X if (c==EOF || c=='\n') break;
- X *t++ = c;
- X }
- X *t = '\0';
- X}
- X
- do_nx()
- X{
- X char fname[100], *f;
- X f=fname;
- X if (skipsp()) return;
- X for (;;) switch(c=suck()) {
- X case EOF:
- X case '\n':
- X case ' ':
- X case '\t':
- X if (f==fname) return;
- X goto got_nx;
- X default:
- X *f++ = c;
- X }
- got_nx:
- X fclose(File);
- X *f = '\0';
- X if (!(File=fopen(fname,"r"))) {
- X fprintf(stderr,"roff: cannot read %s\n",fname);
- X exit(1);
- X }
- X}
- X
- int
- skipsp()
- X{
- X for (;;) switch(c=suck()) {
- X case EOF:
- X case '\n':
- X return 1;
- X case ' ':
- X case '\t':
- X continue;
- X default:
- X ungetc(c,File);
- X return 0;
- X }
- X}
- X
- writebreak()
- X{
- X int q;
- X if (assylen) writeline(0,1);
- X q = TXTLEN;
- X if (o_bl) {
- X if (o_bl + line_no > q) {
- X endpage();
- X beginpage();
- X }
- X for (; o_bl; o_bl--) blankline();
- X }
- X else if (o_sp) {
- X if (o_sp + line_no > q) newpage();
- X else if (line_no) for (; o_sp; o_sp--) blankline();
- X }
- X}
- X
- blankline()
- X{
- X if (line_no >= TXTLEN) newpage();
- X if (o_n2) o_n2++;
- X spit('\n');
- X line_no++;
- X}
- X
- writeline(adflag,flushflag)
- int adflag, flushflag;
- X{
- X int j, q;
- X char lnstring[7];
- X for (j=assylen-1; j; j--) {
- X if (assyline[j]==' ') assylen--;
- X else break;
- X }
- X q = TXTLEN;
- X if (line_no >= q) newpage();
- X for (j=0; j<o_po; j++) spit(' ');
- X if (o_n1) {
- X if (o_nn) for (j=0; j<o_ni+4; j++) spit(' ');
- X else {
- X for (j=0; j<o_ni; j++) spit(' ');
- X sprintf(lnstring,"%3d ",line_no+1);
- X spits(lnstring);
- X }
- X }
- X if (o_n2) {
- X if (o_nn) for (j=0; j<o_ni+4; j++) spit(' ');
- X else {
- X for (j=0; j<o_ni; j++) spit(' ');
- X sprintf(lnstring,"%3d ",o_n2++);
- X spits(lnstring);
- X }
- X }
- X if (o_nn) o_nn--;
- X if (o_ce) for (j=0; j<(o_ll-assylen+1)/2; j++) spit(' ');
- X else for (j=0; j<IDTLEN; j++) spit(' ');
- X if (adflag && !flushflag) fillline();
- X for (j=0; j<assylen; j++) spit(assyline[j]);
- X spit('\n');
- X assylen=0;
- X assyline[0]='\0';
- X line_no++;
- X for (j=1; j<o_ls; j++) if (line_no <= q) blankline();
- X if (!flushflag) {
- X if (o_hc) dehyph(holdword);
- X strcpy(assyline,holdword);
- X assylen=strlen(holdword);
- X *holdword='\0';
- X holdp=holdword;
- X }
- X if (o_ix>=0) o_in=o_ix;
- X o_ix = o_ti = -1;
- X}
- X
- fillline()
- X{
- X int excess, j, s, inc, spaces;
- X adjtoggle^=1;
- X if (!(excess = o_ll - IDTLEN - assylen)) return;
- X if (excess < 0) {
- X fprintf(stderr,"roff: internal error #2 [%d]\n",excess);
- X exit(1);
- X }
- X for (j=2;; j++) {
- X if (adjtoggle) {
- X s=0;
- X inc = 1;
- X }
- X else {
- X s=assylen-1;
- X inc = -1;
- X }
- X spaces=0;
- X while (s>=0 && s<assylen) {
- X if (assyline[s]==' ') spaces++;
- X else {
- X if (0<spaces && spaces<j) {
- X insrt(s-inc);
- X if (inc>0) s++;
- X if (!--excess) return;
- X }
- X spaces=0;
- X }
- X s+=inc;
- X }
- X }
- X}
- X
- insrt(p)
- int p;
- X{
- X int i;
- X for (i=assylen; i>p; i--) assyline[i]=assyline[i-1];
- X assylen++;
- X}
- X
- newpage()
- X{
- X if (page_no >= 0) endpage();
- X else page_no=1;
- X for (; o_sk; o_sk--) blankpage();
- X beginpage();
- X}
- X
- beginpage()
- X{
- X int i;
- X if (sflag) waitawhile();
- X for (i=0; i<o_m1; i++) spit('\n');
- X writetitle(page_no&1? ohead: ehead);
- X for (i=0; i<o_m2; i++) spit('\n');
- X line_no=0;
- X}
- X
- endpage()
- X{
- X int i;
- X for (i=line_no; i<TXTLEN; i++) blankline();
- X for (i=0; i<o_m3; i++) spit('\n');
- X writetitle(page_no&1? ofoot: efoot);
- X for (i=0; i<o_m4; i++) spit('\n');
- X if (o_bp < 0) page_no++;
- X else {
- X page_no = o_bp;
- X o_bp = -1;
- X }
- X}
- X
- blankpage()
- X{
- X int i;
- X if (sflag) waitawhile();
- X for (i=0; i<o_m1; i++) spit('\n');
- X writetitle(page_no&1? ohead: ehead);
- X for (i=0; i<o_m2; i++) spit('\n');
- X for (i=0; i<TXTLEN; i++) spit('\n');
- X for (i=0; i<o_m3; i++) spit('\n');
- X writetitle(page_no&1? ofoot: efoot);
- X page_no++;
- X for (i=0; i<o_m4; i++) spit('\n');
- X line_no=0;
- X}
- X
- waitawhile()
- X{
- X int nix(), oldflags;
- X if (isatty(0)) {
- X oldflags=tty.sg_flags;
- X tty.sg_flags &= ~ECHO; /* DON'T ECHO THE RUBOUT */
- X stty(0,&tty);
- X }
- X signal(SIGINT,nix);
- X pause();
- X if (isatty(0)) {
- X tty.sg_flags = oldflags;
- X stty(0,&tty);
- X }
- X}
- X
- nix()
- X{}
- X
- writetitle(t)
- char *t;
- X{
- X char d, *pst, *pgform();
- X int j, l, m, n;
- X d = *t;
- X if (o_hx || !d) {
- X spit('\n');
- X return;
- X }
- X pst=pgform();
- X for (j=0; j<o_po; j++) spit(' ');
- X l=titlen(++t,d,strlen(pst));
- X while (*t && *t!=d) {
- X if (*t=='%') spits(pst);
- X else spit(*t);
- X t++;
- X }
- X if (!*t) {
- X spit('\n');
- X return;
- X }
- X m=titlen(++t,d,strlen(pst));
- X for (j=l; j<(o_ll-m)/2; j++) spit(' ');
- X while (*t && *t!=d) {
- X if (*t=='%') spits(pst);
- X else spit(*t);
- X t++;
- X }
- X if (!*t) {
- X spit('\n');
- X return;
- X }
- X if ((o_ll-m)/2 > l) m+=(o_ll-m)/2;
- X else m+=l;
- X n=titlen(++t,d,strlen(pst));
- X for (j=m; j<o_ll-n; j++) spit(' ');
- X while (*t && *t!=d) {
- X if (*t=='%') spits(pst);
- X else spit(*t);
- X t++;
- X }
- X spit('\n');
- X}
- X
- char *
- pgform()
- X{
- X static char pst[11];
- X int i;
- X if (o_ro) {
- X *pst='\0';
- X i=page_no;
- X if (i>=400) {
- X strcat(pst,"cd");
- X i-=400;
- X }
- X while (i>=100) {
- X strcat(pst,"c");
- X i-=100;
- X }
- X if (i>=90) {
- X strcat(pst,"xc");
- X i-=90;
- X }
- X if (i>=50) {
- X strcat(pst,"l");
- X i-=50;
- X }
- X if (i>=40) {
- X strcat(pst,"xl");
- X i-=40;
- X }
- X while (i>=10) {
- X strcat(pst,"x");
- X i-=10;
- X }
- X if (i>=9) {
- X strcat(pst,"ix");
- X i-=9;
- X }
- X if (i>=5) {
- X strcat(pst,"v");
- X i-=5;
- X }
- X if (i>=4) {
- X strcat(pst,"iv");
- X i-=4;
- X }
- X while (i--) strcat(pst,"i");
- X }
- X else sprintf(pst,"%d",page_no);
- X return pst;
- X}
- X
- int
- titlen(t,c,k)
- char *t, c;
- int k;
- X{
- X int q;
- X q=0;
- X while (*t && *t!=c) q += *t++ == '%' ? k : 1;
- X return q;
- X}
- X
- spits(s)
- char *s;
- X{
- X while (*s) spit(*s++);
- X}
- X
- spit(c)
- char c;
- X{
- X static int col_no, n_blanks;
- X int ulflag;
- X char *t;
- X ulflag=c&UNDERL;
- X c&=~UNDERL;
- X for (t = (char *)o_tr; *t; t++) if (*t++==c) {
- X/*
- X * fix - last char translates to space.
- X */
- X c = *t? *t: ' ';
- X break;
- X }
- X if (page_no < startpage || (stoppage && page_no > stoppage)) return;
- X if (c != ' ' && c != '\n' && n_blanks) {
- X if (hflag && n_blanks>1)
- X while (col_no/8 < (col_no+n_blanks)/8) {
- X putc('\t',stdout);
- X n_blanks-= 8 - (col_no & 07);
- X col_no = 8 + col_no & ~07;
- X }
- X for (; n_blanks; n_blanks--) {
- X putc(' ',stdout);
- X col_no++;
- X }
- X }
- X if (ulflag && isalnum(c)) fputs("_\b",stdout);
- X if (c == ' ') n_blanks++;
- X else {
- X putc(c,stdout);
- X col_no++;
- X }
- X if (c == '\n') {
- X col_no=0;
- X n_blanks=0;
- X }
- X}
- X
- int
- suck()
- X{
- X for (;;) {
- X c=getc(File);
- X if (islegal(c)) return c;
- X }
- X}
- X
- X/*
- X * strhas - does string have character? Allow UNDERL flag.
- X */
- X
- char *
- strhas(p,c)
- char *p, c;
- X{
- X for (; *p; p++) if ((*p&~UNDERL)==c) return p;
- X return NULL;
- X}
- X
- X/*
- X * strend - find NULL at end of string.
- X */
- X
- char *
- strend(p)
- char *p;
- X{
- X while (*p++);
- X return p;
- X}
- X
- X/*
- X * isspace, isalnum, isdigit, islegal - classify a character.
- X * We could just as well use <ctype.h> if it didn't vary from
- X * one version of Unix to another. As it is, these routines
- X * must be modified for weird character sets, like EBCDIC and
- X * CDC Scientific.
- X */
- X
- int
- isspace(c)
- int c;
- X{
- X char *s;
- X for (s=spacechars; *s; s++) if (*s==c) return 1;
- X return 0;
- X}
- X
- int
- isalnum(c)
- int c;
- X{
- X return (c>='A'&&c<='Z') || (c>='a'&&c<='z') || (c>='0'&&c<='9');
- X}
- X
- int
- isdigit(c)
- int c;
- X{
- X return c>='0' && c<='9';
- X}
- X
- int
- islegal(c)
- int c;
- X{
- X return c>=' ' && c<='~' || isspace(c) || c=='\n' || c==EOF;
- X}
- X
- bomb()
- X{
- X fprintf(stderr,"usage: roff [+00] [-00] [-s] [-h] file ...\n");
- X exit(1);
- X}
- END_OF_FILE
- if test 20604 -ne `wc -c <'roff.c'`; then
- echo shar: \"'roff.c'\" unpacked with wrong size!
- fi
- # end of 'roff.c'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(384 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- DESTROOT=
- DESTPATH=$(DESTROOT)/usr/local
- BIN=$(DESTPATH)/bin
- MAN=$(DESTPATH)/man
- CFLAGS= -O
- X
- all: roff
- X
- roff: roff.o
- X cc -o roff roff.o
- X
- install: roff roff.1
- X (echo ".ds Bd $(BIN)"; cat roff.1) > $(MAN)/man1/roff.1
- X -rm -f $(BIN)/roff
- X -cp roff $(BIN)/roff
- X
- shar: roff.shar
- X
- roff.shar: Makefile roff.1 roff.c
- X shar Makefile roff.1 roff.c > roff.shar
- X
- clean:
- X rm -f *.o roff roff.shar
- END_OF_FILE
- if test 384 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- echo shar: End of shell archive.
- exit 0
-